约瑟夫环问题的一种描述

/*
约瑟夫环问题的一种描述是:编号为1,2,3,?,n的n个人按顺时针方向围坐一圈,每人手持一个密码(正整数)。
一开始任选一个整数作为报数上限值,从第一人开始顺时针自1开始顺序报数,报到m时停止报数。
报m的人出列,将它的密码作为新的m值,从他在顺时针方向上的下一个人开始重新从1报数,如此下去直到所有人全部出列为止。
试设计程序实现之。
*/

#include"stdio.h"

#include"malloc.h"

//1.元素类型,结点类型和指针类型

typedef struct LNode         //定义结构体,

{

 int num,pwd;                 //num用来存储人的序号,pwd用来存储人的密码

 struct LNode *next;

};

struct LNode *head,*p,*pt;    //定义结点

//2 、创建循环链表函数

 

int creatLinkList(int n)      //参数n传递人数,

{

   int i;

   head=(struct LNode*)malloc(sizeof(struct LNode));   //创建一个带头结点的链表

   if(!head)  {return 0;}    //创建不成功,返回0

   p=head;

   for(i=1;i<n;i++)

  {

     pt=(struct LNode*)malloc(sizeof(struct LNode));

     if(!pt)  {return 0;}

     p->next=pt;

     p=pt;

  }

    p->next=head; //构成循环链表

    pt=head;

return 0;

}

//3.创建输入密码函数

 int enterPwd(int n)        //参数n传递人数

{

   int i,j;

   printf("\n请输入密码: \n");

    for( i=1;i<=n;i++)

    {

       scanf("%d",&j);

       pt->num=i;        //num存储人的序号

       pt->pwd=j;         //pwd存储人的密码

       pt=pt->next;

    }

    pt=p;

return j;

}

 //4、创建输出函数

 int outList(int m,int n)    //参数m、n传递报数上限值和人数

{

   int i,a;

   for(i=1;i<=n;i++)         //用一个for循环搜索循环链表

   {

      for(a=1;a<m;a++)      //删除结点

      {

        pt=pt->next;

      }

      p=pt->next;

      m=p->pwd;

      printf("%d ",p->num);    //输出人的序号

      pt->next=p->next;

      free(p);          //释放动态申请的结点空间

   }

   return 0;

}

 //主函数

void main()

{   int m,n;   //m为报数上限值,n为人数

    printf("\n参数m、n传递报数上限值和人数;\n");

    printf("\n请输入 m 和n: \n");

    scanf("%d %d",&m,&n);

    creatLinkList( n);  //调用创建链表函数

    enterPwd( n);       //调用输入密码函数

    printf("\n出队的人依次是:\n");

    outList( m,n);      //调用输出链表函数

}

### 回答1: 限m,从第一个人开始按顺时针方向自1开始顺序报数,报到m的人出圈,直到剩下最后一个人为止。这个人就是约瑟夫的胜利者。解决约瑟夫环问题的方法有很多,其中比较常用的是递归和数学公式法。递归法是通过递归函数模拟报数和出圈的过程,直到只剩下一个人为止。数学公式法则是通过数学公式计算出最后一个出圈的人的编号。无论采用哪种方法,都需要理解约瑟夫环问题的本质和规律,才能得出正确的解答。 ### 回答2: 约瑟夫环问题是经典的数学问题,它的背景故事大家都比较熟知,就是n个人围成一圈,依次报数,报到m的人出圈,问最后剩下的人在原来序列中的编号是多少。这个问题在我们的生活中可能不常见,但在计算机领域中却是经常被用到的。 本文将介绍三种常见的解决约瑟夫环问题的方法。 第一种方法是使用循链表。我们可以用一个循链表来模拟这个过程,每次找到要出圈的人,然后删除节点。直到只剩下一个节点为止。使用循链表的优点是简单易懂,但是需要手写链表结构,增加了代码量。 第二种方法是使用递归。我们可以使用一个递归函数来模拟这个过程,首先定义f(n,m)为n个人报数,每报m个人出圈最后胜利者的编号。那么在这个过程中,每次出圈的人都是(m-1)%n,这样我们就可以使用递归,逐步缩小n的范围,最后得到结果。使用递归的优点是代码量少,但是由于递归的特点,当数据量大的时候,可能会导致栈溢出。 第三种方法是使用数学公式。约瑟夫环问题有一个非常简单的数学规律,每次出圈的人可以表示为:(f(n-1,m)+m-1)%n+1,其中f(n-1,m)表示n-1个人时的所求编号,这个方法的优点是速度快,但是需要较高的数学能力。 这三种方法各有优缺点,可以根据具体问题的需求进行选择。总之,约瑟夫环问题虽然表面上只是一个简单的数学问题,但是其中蕴含的思维逻辑和算法原理非常深刻,是值得我们在日常练习中多多涉猎和思考的。 ### 回答3: 当报数为k时,第一次报数为k的人从顺时针方向开始依次出列,之后从他的下一个人重新开始报数,仍然是从k开始报数,直到所有人被排出圈子。该问题的实现方式有多种,其中较为常见的是使用单向循链表实现。 对于n个人排成的队列,可以使用循链表的形式存储,每个节点存储一个人的编号和密码。为了方便计算,可以给每个人编号从0到n-1。同时,为了实现报数为k的轮换,可以使用一个计数器j表示当前报数的人的编号,每报数一次则将j加1,当j等于k时,表示该人要被出列。具体实现可以利用模运算,即(j+k)%n表示要出列的人的编号,将该人从链表中移除,直到只剩下最后一个人为止。 另外,该问题也可以使用递推公式求解。令f(n,k)表示n个人报数为k时最后剩下的人的编号,则有以下递推关系式: f(1,k) = 0 f(n,k) = (f(n-1,k) + k) % n 其中f(1,k)表示只有一个人时,其编号为0;f(n,k)表示n个人中报数为k的轮换中最后剩下的人的编号;(f(n-1,k) + k) % n表示在n-1个人中报数为k时的轮换中最后剩下的人的编号,再加上k得到n个人中报数为k时的轮换最后剩下的人的编号。 通过递推公式,可以较为快速地求解较大规模问题的解,避免使用链表等数据结构引发的空间复杂度过高的问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值